package com.gopay.common.user.manager.impl;

import com.gopay.common.cipher.utils.LoggerMaskUtils;
import com.gopay.common.cipher.utils.SensitiveInfoUtils;
import com.gopay.common.constants.trans.CertChannelCode;
import com.gopay.common.constants.trans.CustCategory;
import com.gopay.common.constants.trans.CustChannelNum;
import com.gopay.common.domain.cust.CustPersonInfo;
import com.gopay.common.domain.cust.CustRealNameCertifyLog;
import com.gopay.common.domain.user.identify.PersCertChannelDTL;
import com.gopay.common.order.dao.CommonQueryDAO;
import com.gopay.common.user.dao.CustPersonInfoQueryDAO;
import com.gopay.common.user.dao.CustRealNameCertifyLogDAO;
import com.gopay.common.user.dao.PersCertChannelDtlDao;
import com.gopay.common.user.manager.PersonThreeAccountChannelManager;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 个人三类账户插入认证渠道统一口径实现类
 * Created by Lenovo-songfengli on 2016/10/31.
 */
@Service("personThreeAccountChannelManager")
public class PersonThreeAccountChannelManagerImpl implements PersonThreeAccountChannelManager{
    protected final static Log logger = LogFactory.getLog(PersonThreeAccountChannelManagerImpl.class);

    @Resource(name = "commonQueryDAO")
    private CommonQueryDAO commonQueryDAO;

    @Resource(name = "persCertChannelDtlDao")
    private PersCertChannelDtlDao persCertChannelDtlDao;

    @Resource(name = "custRealNameCertifyLogDAO")
    private CustRealNameCertifyLogDAO custRealNameCertifyLogDAO;

    @Resource(name = "custPersonInfoQueryDao")
    private CustPersonInfoQueryDAO custPersonInfoQueryDAO;

    private static final String CHANNEL_STATUS_SUCCESS = "01"; //认证状态成功

    private static final String CHANNEL_STATUS_DISABLED = "99"; //认证状态成功但不可用

    private static final int FACE_CHANNEL_NUM = 5;  //人脸识别认证渠道的数量

    private static final String TOTAL_FACE_CHANNEL_CODE = "40";  //总人脸识别

    private  String[] faceChannelCodeArray = {"41","42","43","44","45"};  //将总人脸识别拆分成5个人脸识别渠道

    @Override
    public  void savePersCertChannel(PersCertChannelDTL persCertChannelDTL){
        //1.三类账户校验（261文）
        if(CHANNEL_STATUS_SUCCESS.equals(persCertChannelDTL.getStatus())
                && checkThreeAccount(persCertChannelDTL.getCertNo(),persCertChannelDTL.getCustId()) ){
            persCertChannelDTL.setStatus(CHANNEL_STATUS_DISABLED);
        }

        //由于国政通不在合作，则需要将实名认证的渠道转化为中诚信（或者中诚信原）
        // 但是cron中的国政通则还需要进行实名，直到咋们在国政通账户里的钱用完为止
        if(CertChannelCode.GZT.value.equals(persCertChannelDTL.getChannelCode())){
            logger.info("这是用国政通做的实名认证，需要将渠道进行转化，客户ID为："+persCertChannelDTL.getCustId());
            CustPersonInfo info = custPersonInfoQueryDAO.find(CustPersonInfo.class, persCertChannelDTL.getCustId());
            if(null != info){
                CustRealNameCertifyLog log =
                        custRealNameCertifyLogDAO.findByCertNoAndName(persCertChannelDTL.getCertNo(),info.getCustName());
                if(null != log && StringUtils.isNotBlank(log.getChannelCode())){
                    persCertChannelDTL.setChannelCode(log.getChannelCode());
                }
            }
        }

        //2.保存认证渠道
        if(! findIsCertChannel(persCertChannelDTL)){
            logger.info("该认证渠道没有，需要插入认证渠道，客户id是:"+persCertChannelDTL.getCustId()+
                    ",渠道代码是:"+persCertChannelDTL.getChannelCode()+",状态是:"+persCertChannelDTL.getStatus());

            if(TOTAL_FACE_CHANNEL_CODE.equals(persCertChannelDTL.getChannelCode())){  //人脸人别渠道
                for(int i = 0;i < FACE_CHANNEL_NUM;i++){
                    PersCertChannelDTL newPersCertChannelDtl = new PersCertChannelDTL();
                    newPersCertChannelDtl.setCertNo(persCertChannelDTL.getCertNo());
                    newPersCertChannelDtl.setCustId(persCertChannelDTL.getCustId());
                    newPersCertChannelDtl.setChannelCode(faceChannelCodeArray[i]);
                    newPersCertChannelDtl.setStatus(persCertChannelDTL.getStatus());
                    newPersCertChannelDtl.setCreatedOperId(persCertChannelDTL.getCreatedOperId());
                    newPersCertChannelDtl.setCreatedTs(persCertChannelDTL.getCreatedTs());
                    newPersCertChannelDtl.setRemark("人脸识别认证渠道");
                    if(CHANNEL_STATUS_SUCCESS.equals(newPersCertChannelDtl.getStatus())
                    && checkThreeAccount(newPersCertChannelDtl.getCertNo(),newPersCertChannelDtl.getCustId())){
                        newPersCertChannelDtl.setStatus(CHANNEL_STATUS_DISABLED);
                    }
                    persCertChannelDtlDao.save(newPersCertChannelDtl);
                }
            }else{ //其他渠道
                persCertChannelDtlDao.save(persCertChannelDTL);
            }
        }
    }

    @Override
    public boolean isTransferCertChannel(String certNo,String custId){
        //1.判断该custId是几类账户
        String custCategory=CustChannelNum.custType(persCertChannelDtlDao.findSuccessCertChannelCountsByCustId(custId));
        logger.info("该认证渠道的custId:"+custId+"账户类型是:"+custCategory);
        if(CustCategory.three.value.equals(custCategory)) {
            return false;
        }
        //2.查询该身份证号下是否已有三类账户,并且该账户是否为二类账户，是否满足261文档
        Map<String, Object> param = new HashMap<>();
        //ssj 20170605 身份证号加解密查询
        param.put("hisCertNoList",SensitiveInfoUtils.getAllHisCipherText(certNo).toArray());
        List<Object[]> accountCategory =  commonQueryDAO.findBySql(buildSQL(),param);
        if(null != accountCategory && accountCategory.size() > 0){
            logger.info("该身份证号下的三类账户custId是:"+accountCategory.get(0)[1]);
            if(CustCategory.two.value.equals(custCategory)
                    || CustCategory.three.value.equals(custCategory)){
                return false;
            }
        }
        return true;
    }

    /**
     * 三类账户校验(261文)
     * @param certNo 身份证号
     *@param custId 客户id
     * @return   true已满足 false 不满足
     */
    private boolean checkThreeAccount(String certNo,String custId){
        //modified by zyt，对日志中敏感字段做掩码显示
        //logger.info("该身份证号是:"+certNo+"，该认证渠道的custId:"+custId);
        logger.info("该身份证号是:" + LoggerMaskUtils.maskString(certNo) + "，该认证渠道的custId:" + custId);
        int custChannelNum = persCertChannelDtlDao.findSuccessCertChannelCountsByCustId(custId);
        logger.info("客户custId认证渠道的个数为："+custChannelNum);
        if((CustChannelNum.three.num - 1) == custChannelNum){
            Map<String, Object> param = new HashMap<>();
            /**
             * modified by zyt 2017-4-13 加密字段查询使用in
             */
            //start++++++++++
            List<String> hisCertNoList = SensitiveInfoUtils.getAllHisCipherText(certNo);
            param.put("hisCertNoList", hisCertNoList.toArray());
            //end++++++++++++
            List<Object[]> highaccount =  commonQueryDAO.findBySql(buildSQL(),param);
            if(null != highaccount && highaccount.size() > 0){
                logger.info("该身份证号是:" + LoggerMaskUtils.maskString(certNo) + "，该认证渠道的custId:" + custId +
                        "该身份证号下的三类账户custId是:"+highaccount.get(0)[1]);
                return true;
            }else{
                return false;
            }
        }else{
            return false;
        }
    }

    private String buildSQL(){
        StringBuffer sql = new StringBuffer();
        sql.append(" select a.highcustcategory,a.cust_id from ");
        sql.append(" (select (case when count(*) >=" );
        sql.append(CustChannelNum.three.num);
        sql.append(" then '");
        sql.append(CustCategory.three.value);
        sql.append("' when count(*) >=");
        sql.append(CustChannelNum.two.num);
        sql.append(" then '");
        sql.append(CustCategory.two.value);
        sql.append("' when count(*) >=");
        sql.append(CustChannelNum.one.num);
        sql.append(" then '");
        sql.append(CustCategory.one.value);
        sql.append("' else '' end) as highcustcategory,cust_id ");
        sql.append("  from pers_cert_channel_dtl where status = '01' ");
        /**
         * modified by zyt 2017-4-13 加密字段查询使用in
         */
        //sql.append("  and cert_no = :certNo");
        sql.append("  and cert_no in (:hisCertNoList)");
        /**
         * modified by zyt，根据fongfengli说明修改，注释掉按身份证号分组
         */
        sql.append("  group by cust_id order by highcustcategory desc ) a ");
        //sql.append("  group by cert_no, cust_id order by highcustcategory desc ) a ");
        sql.append("  where rownum=1 and a.highcustcategory ='");
        sql.append(CustCategory.three.value);
        sql.append("'");
        return sql.toString();
    }

    private  boolean findIsCertChannel(PersCertChannelDTL persCertChannelDTL) {
        StringBuffer querysql = new StringBuffer();
        querysql.append(" select count(*) from pers_cert_channel_dtl t where t.cust_id = :custId and t.channel_code = :channelCode ");
        if(StringUtils.isNotBlank(persCertChannelDTL.getCardNo())){
        	/**
        	 * modified by zyt 敏感字段的查询使用in
        	 * 2017-2-28
        	 */
        	querysql.append(" and t.card_no in (:hisNoList) ");
            //querysql.append(" and t.card_no = :cardNo ");
        }
        querysql.append(" and (t.status ='");
        querysql.append(CHANNEL_STATUS_SUCCESS);
        querysql.append("' or t.status = '");
        querysql.append(CHANNEL_STATUS_DISABLED);
        querysql.append("') ");
        Map<String, Object> tmap = new HashMap<>();
        tmap.put("custId",persCertChannelDTL.getCustId());
        tmap.put("channelCode",persCertChannelDTL.getChannelCode());
        if(StringUtils.isNotBlank(persCertChannelDTL.getCardNo())){
        	/**
        	 * modified by zyt 敏感字段的查询使用in，传入参数
        	 * 2017-2-28
        	 */
            List<String> hisNoList = SensitiveInfoUtils.getAllHisCipherText(persCertChannelDTL.getCardNo());
            tmap.put("hisNoList",hisNoList.toArray());
        }
        if(commonQueryDAO.findCountBySql(querysql.toString(),tmap) > 0){
            return true;
        }
           return false;
    }
}
